home *** CD-ROM | disk | FTP | other *** search
- /*
-
- function.c
-
- This software is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this software; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Original copyright notice follows:
-
- Copyright, 1993, Brent Benson. All Rights Reserved.
- 0.4 & 0.5 Revisions Copyright 1994, Joseph N. Wilson. All Rights Reserved.
-
- Permission to use, copy, and modify this software and its
- documentation is hereby granted only under the following terms and
- conditions. Both the above copyright notice and this permission
- notice must appear in all copies of the software, derivative works
- or modified version, and both notices must appear in supporting
- documentation. Users of this software agree to the terms and
- conditions set forth in this notice.
-
- */
-
- #include <string.h>
-
- #include "function.h"
-
- #include "apply.h"
- #include "class.h"
- #include "env.h"
- #include "error.h"
- #include "eval.h"
- #include "keyword.h"
- #include "list.h"
- #include "number.h"
- #include "prim.h"
- #include "symbol.h"
- #include "values.h"
- #include "vector.h"
-
- extern Object x_symbol;
-
- /* local function prototypes */
-
- static Object generic_function_make (Object arglist);
- static Object generic_function_methods (Object gen);
- static Object generic_function_mandatory_keywords (Object generic);
- static Object function_specializers (Object func);
- static Object function_values (Object func);
- static Object make_specializers_from_params (Object);
- static Object function_specializers_help (Object params);
- static Object function_arguments (Object fun);
- static Object user_applicable_method_p (Object fun, Object sample_args);
- static Object applicable_method_p (Object fun,
- Object sample_args,
- int strict_check);
- static Object sort_methods (Object methods, Object sample_args);
- static int sort_driver (Object *pmeth1, Object *pmeth2);
- static int same_specializers (Object s1, Object s2);
- static int specializer_compare (Object spec1, Object spec2);
- static Object find_method (Object generic, Object spec_list);
- static Object remove_method (Object generic, Object method);
- static Object debug_name_setter (Object method, Object name);
-
- /* primitives */
-
- static struct primitive function_prims[] =
- {
- {"%add-method", prim_2, add_method},
- {"%generic-function-make", prim_1, generic_function_make},
- {"%generic-function-methods", prim_1, generic_function_methods},
- {"%generic-function-mandatory-keywords", prim_1,
- generic_function_mandatory_keywords},
- {"%function-specializers", prim_1, function_specializers},
- {"%function-values", prim_1, function_values},
- {"%function-arguments", prim_1, function_arguments},
- {"%applicable-method?", prim_1_rest, user_applicable_method_p},
- {"%sorted-applicable-methods", prim_1_rest, sorted_applicable_methods},
- {"%find-method", prim_2, find_method},
- {"%remove-method", prim_2, remove_method},
- {"%debug-name-setter", prim_2, debug_name_setter},
- };
-
- /* function definitions */
-
-
- void
- init_function_prims (void)
- {
- int num;
- Object obj_sym, t_sym;
-
- num = sizeof (function_prims) / sizeof (struct primitive);
-
- init_prims (num, function_prims);
- }
-
- static void
- keyword_list_insert (Object *list, Object key_binding)
- {
- Object *tmp_ptr;
- int compare;
- char *key_name;
-
- key_name = SYMBOLNAME (CAR (key_binding));
- /* Search for insert point, then break */
-
- tmp_ptr = list;
- while (PAIRP (*tmp_ptr)) {
- compare = strcmp (key_name, SYMBOLNAME (CAR (CAR (*tmp_ptr))));
- if (compare < 0) {
- tmp_ptr = &CDR (*tmp_ptr);
- } else if (compare > 0) {
- break;
- } else {
- error ("keyword specified twice", CAR (key_binding),
- CAR (CAR (*tmp_ptr)), NULL);
- return;
- }
- }
- *tmp_ptr = cons (key_binding, *tmp_ptr);
- }
-
- static void
- parse_generic_function_parameters (Object gf_obj, Object params)
- {
- Object entry, *tmp_ptr, result_type;
-
- tmp_ptr = &GFREQPARAMS (gf_obj);
- *tmp_ptr = make_empty_list ();
-
- /* first get required params */
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == hash_rest_symbol || entry == key_symbol ||
- entry == hash_values_symbol) {
- break;
- }
- if (PAIRP (entry)) {
- (*tmp_ptr) = cons (listem (CAR (entry),
- eval (SECOND (entry)),
- NULL),
- make_empty_list ());
- } else {
- *tmp_ptr = cons (listem (entry, object_class, NULL),
- make_empty_list ());
- }
- tmp_ptr = &CDR (*tmp_ptr);
- params = CDR (params);
- }
-
- /* next look for rest parameter */
- if (PAIRP (params) && CAR (params) == hash_rest_symbol) {
- params = CDR (params);
- if (PAIRP (params)) {
- GFRESTPARAM (gf_obj) = CAR (params);
- params = CDR (params);
- } else {
- error ("generic function #rest designator not followed by a parameter", NULL);
- }
- } else {
- GFRESTPARAM (gf_obj) = NULL;
- }
- /* next look for key parameters */
- GFKEYPARAMS (gf_obj) = make_empty_list ();
- if (PAIRP (params) && CAR (params) == key_symbol) {
- GFPROPS (gf_obj) |= GFKEYSMASK;
- params = CDR (params);
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == allkeys_symbol) {
- break;
- }
- /* get a keyword-parameter */
- if (SYMBOLP (entry)) {
- keyword_list_insert (&GFKEYPARAMS (gf_obj),
- listem (symbol_to_keyword (entry),
- entry,
- false_object,
- NULL));
- } else if (PAIRP (entry) && SYMBOLP (CAR (entry)) &&
- list_length (entry) == 2) {
- keyword_list_insert (&GFKEYPARAMS (gf_obj),
- listem (symbol_to_keyword (CAR (entry)),
- CAR (entry),
- SECOND (entry),
- NULL));
- } else if (PAIRP (entry) && KEYWORDP (CAR (entry)) &&
- list_length (entry) == 3) {
- keyword_list_insert (&GFKEYPARAMS (gf_obj), entry);
- }
- params = CDR (params);
- }
- if (PAIRP (params) && CAR (params) == allkeys_symbol) {
- GFPROPS (gf_obj) |= GFALLKEYSMASK;
- params = CDR (params);
- if (PAIRP (params) && CAR (params) != hash_values_symbol) {
- error ("parameters follow #all-keys", params);
- }
- }
- }
- /* now get return value types */
- if (PAIRP (params) && CAR (params) == hash_values_symbol) {
- params = CDR (params);
- GFRESTVALUES (gf_obj) = NULL;
- tmp_ptr = &GFREQVALUES (gf_obj);
- *tmp_ptr = make_empty_list ();
-
- /* first get required return values */
- /* first get required return values */
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == hash_rest_symbol) {
- break;
- }
- if (PAIRP (entry)) {
- result_type = eval (SECOND (entry));
- } else {
- result_type = object_class;
- }
-
- (*tmp_ptr) = cons (result_type, make_empty_list ());
- tmp_ptr = &CDR (*tmp_ptr);
- params = CDR (params);
- }
-
- /* next look for rest parameter */
- if (PAIRP (params) && CAR (params) == hash_rest_symbol) {
- params = CDR (params);
- if (PAIRP (params)) {
- if (PAIRP (CAR (params))) {
- GFRESTVALUES (gf_obj) = eval (SECOND (CAR (params)));
- } else {
- GFRESTVALUES (gf_obj) = object_class;
- }
- params = CDR (params);
- } else {
- error ("generic function #rest designator not followed by a parameter", NULL);
- }
- }
- } else { /* no values specified */
- GFREQVALUES (gf_obj) = make_empty_list ();
- GFRESTVALUES (gf_obj) = object_class;
- }
-
- if (PAIRP (params)) {
- error ("objects encountered after parameter list", params, NULL);
- }
- if (trace_functions) {
- warning ("Got GF", GFNAME (gf_obj), NULL);
- warning (" Required parameters", GFREQPARAMS (gf_obj), NULL);
- warning (" Rest parameter", GFRESTPARAM (gf_obj), NULL);
- if (GFHASKEYS (gf_obj)) {
- warning (" Has keys", NULL);
- warning (" Key parameters", GFKEYPARAMS (gf_obj), NULL);
- }
- if (GFALLKEYS (gf_obj)) {
- warning (" All Keys specified", NULL);
- }
- warning (" Required return values", GFREQVALUES (gf_obj), NULL);
- warning (" Rest return value type", GFRESTVALUES (gf_obj), NULL);
- }
- }
-
- Object
- make_generic_function (Object name, Object params, Object methods)
- {
- Object obj;
-
- obj = allocate_object (sizeof (struct generic_function));
-
- GFTYPE (obj) = GenericFunction;
- GFNAME (obj) = name;
- parse_generic_function_parameters (obj, params);
- GFMETHODS (obj) = methods;
- return (obj);
- }
-
- static void
- parse_method_parameters (Object meth_obj, Object params)
- {
- Object entry, *tmp_ptr, result_type;
-
- tmp_ptr = &METHREQPARAMS (meth_obj);
- *tmp_ptr = make_empty_list ();
-
- /* first get required params */
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == hash_rest_symbol || entry == key_symbol ||
- entry == hash_values_symbol || entry == next_symbol) {
- break;
- }
- if (PAIRP (entry)) {
- (*tmp_ptr) = cons (listem (CAR (entry),
- eval (SECOND (entry)),
- NULL),
- make_empty_list ());
- } else {
- *tmp_ptr = cons (listem (entry, object_class, NULL),
- make_empty_list ());
- }
- tmp_ptr = &CDR (*tmp_ptr);
- params = CDR (params);
- }
-
- /* look for next-method parameter */
- if (PAIRP (params) && CAR (params) == next_symbol) {
- params = CDR (params);
- if (PAIRP (params)) {
- METHNEXTMETH (meth_obj) = CAR (params);
- params = CDR (params);
- } else {
- error ("generic function #next designator not followed by a parameter", NULL);
- }
- } else {
- METHNEXTMETH (meth_obj) = next_method_symbol;
- }
-
- /* next look for rest parameter */
- if (PAIRP (params) && CAR (params) == hash_rest_symbol) {
- params = CDR (params);
- if (PAIRP (params)) {
- METHRESTPARAM (meth_obj) = CAR (params);
- params = CDR (params);
- } else {
- error ("generic function #rest designator not followed by a parameter", NULL);
- }
- } else {
- METHRESTPARAM (meth_obj) = NULL;
- }
-
- /* next look for key parameters */
- METHKEYPARAMS (meth_obj) = make_empty_list ();
- if (PAIRP (params) && CAR (params) == key_symbol) {
- params = CDR (params);
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == allkeys_symbol) {
- break;
- }
- /* get a keyword-parameter pair */
- if (SYMBOLP (entry)) {
- keyword_list_insert (&METHKEYPARAMS (meth_obj),
- listem (symbol_to_keyword (entry),
- entry,
- false_object,
- NULL));
- } else if (PAIRP (entry) && SYMBOLP (CAR (entry)) &&
- list_length (entry) == 2) {
- keyword_list_insert (&METHKEYPARAMS (meth_obj),
- listem (symbol_to_keyword (CAR (entry)),
- CAR (entry),
- SECOND (entry),
- NULL));
- } else if (PAIRP (entry) && KEYWORDP (CAR (entry)) &&
- list_length (entry) == 3) {
- keyword_list_insert (&METHKEYPARAMS (meth_obj), entry);
- }
- params = CDR (params);
- }
- }
- if (PAIRP (params) && CAR (params) == allkeys_symbol) {
- METHPROPS (meth_obj) |= METHALLKEYSMASK;
- params = CDR (params);
- if (PAIRP (params) && CAR (params) != hash_values_symbol) {
- error ("parameters follow #all-keys", params);
- }
- }
- /* now get return value types */
- if (PAIRP (params) && CAR (params) == hash_values_symbol) {
- params = CDR (params);
- METHRESTVALUES (meth_obj) = NULL;
- tmp_ptr = &METHREQVALUES (meth_obj);
- *tmp_ptr = make_empty_list ();
-
- /* first get required return values */
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
- if (entry == hash_rest_symbol) {
- break;
- }
- if (PAIRP (entry)) {
- result_type = eval (SECOND (entry));
- } else {
- result_type = object_class;
- }
-
- (*tmp_ptr) = cons (result_type, make_empty_list ());
- tmp_ptr = &CDR (*tmp_ptr);
- params = CDR (params);
- }
-
- /* next look for rest parameter */
- if (PAIRP (params) && CAR (params) == hash_rest_symbol) {
- params = CDR (params);
- if (PAIRP (params)) { /* need structure check */
- if (PAIRP (CAR (params))) {
- METHRESTVALUES (meth_obj) = eval (SECOND (CAR (params)));
- } else {
- METHRESTVALUES (meth_obj) = object_class;
- }
- params = CDR (params);
- } else {
- error ("function #rest designator not followed by a parameter", NULL);
- }
- }
- } else {
- METHREQVALUES (meth_obj) = make_empty_list ();
- METHRESTVALUES (meth_obj) = object_class;
- }
-
- if (PAIRP (params)) {
- error ("objects encountered after parameter list", params, NULL);
- }
- if (trace_functions) {
- warning ("Got Method", METHNAME (meth_obj), NULL);
- warning (" Required parameters", METHREQPARAMS (meth_obj), NULL);
- warning (" Rest parameter", METHRESTPARAM (meth_obj), NULL);
- warning (" Key parameters", METHKEYPARAMS (meth_obj), NULL);
- if (METHALLKEYS (meth_obj)) {
- warning ("All Keys specified", NULL);
- }
- warning (" Required return values", METHREQVALUES (meth_obj), NULL);
- warning (" Rest return value type", METHRESTVALUES (meth_obj), NULL);
- }
- }
-
- static Object
- create_generic_parameters (Object params)
- {
- Object entry, gf_params;
-
- gf_params = make_empty_list ();
-
- /* first get required params */
- while (PAIRP (params)) { /* CONTAINS BREAK! */
- entry = CAR (params);
-
- if (entry == hash_rest_symbol) { /* skip #rest */
- params = CDR (params);
- if (PAIRP (params)) {
- params = CDR (params);
- } else {
- error ("method #rest designator not followed by a parameter", NULL);
- }
- break;
- }
- /* don't convert #key or #value */
- if (entry == key_symbol || entry == hash_values_symbol) {
- break;
- }
- if (PAIRP (entry)) {
- entry = CAR (entry);
- }
- gf_params = append (gf_params, listem (entry, NULL));
-
- params = CDR (params);
- }
-
- /* next add generic rest parameter */
- gf_params = append (gf_params, listem (hash_rest_symbol, NULL));
- gf_params = append (gf_params, listem (x_symbol, NULL));
-
- /* I believe that all other parts of the generic function parameters
- ** should be the same as the initial method's
- */
- if (PAIRP (params)) {
- gf_params = append (gf_params, params);
- }
- return (gf_params);
- }
-
- Object
- make_method (Object name, Object params, Object body, struct frame *env, int do_generic)
- {
- Object obj, gf;
-
- obj = allocate_object (sizeof (struct method));
-
- METHTYPE (obj) = Method;
- if (name) {
- METHNAME (obj) = name;
- } else {
- METHNAME (obj) = NULL;
- }
- parse_method_parameters (obj, params);
- METHBODY (obj) = body;
- METHENV (obj) = env;
- if (do_generic && name) {
- gf = symbol_value (name);
- if (!gf) {
- gf = make_generic_function (name,
- create_generic_parameters (params),
- make_empty_list ());
- add_top_level_binding (name, gf, 0);
- }
- add_method (gf, obj);
- return (gf);
- } else {
- return (obj);
- }
- }
-
- Object
- make_next_method (Object rest_methods, Object args)
- {
- Object obj;
-
- obj = allocate_object (sizeof (struct next_method));
-
- NMTYPE (obj) = NextMethod;
- NMREST (obj) = rest_methods;
- NMARGS (obj) = args;
- return (obj);
- }
-
- static Object
- generic_function_make (Object arglist)
- {
- Object obj;
- Object required, rest, key, allkeys;
- Object ptr;
-
- required = FIRST (arglist);
- arglist = CDR (arglist);
- rest = FIRST (arglist);
- arglist = CDR (arglist);
- key = FIRST (arglist);
- arglist = CDR (arglist);
- allkeys = FIRST (arglist);
-
- for (ptr = required; PAIRP (ptr); ptr = CDR (ptr)) {
- if (!CLASSP (CAR (ptr))) {
- error ("make: generic function specializer is not a class",
- CAR (ptr),
- NULL);
- } else {
- CAR (ptr) = listem (unspecified_object, CAR (ptr), NULL);
- }
- }
-
- obj = allocate_object (sizeof (struct generic_function));
-
- GFTYPE (obj) = GenericFunction;
- GFNAME (obj) = unspecified_object;
- GFREQPARAMS (obj) = required;
-
- if (rest != false_object) {
- GFRESTPARAM (obj) = rest;
- } else {
- GFRESTPARAM (obj) = NULL;
- }
- GFKEYPARAMS (obj) = key;
- if (allkeys == false_object) {
- GFPROPS (obj) &= !GFALLKEYSMASK;
- } else {
- GFPROPS (obj) |= GFALLKEYSMASK;
- }
- GFMETHODS (obj) = make_empty_list ();
- return (obj);
-
- }
-
- Object
- make_generic_function_driver (Object args)
- {
- error ("make: not implemented for generic functions", NULL);
- }
-
- /* local functions */
-
- /* compare specializer lists s1 and s2 to see if each specializer in s1
- * is a subclass of the corresponding specializer in s2
- * list lengths are also compared.
- */
- static int
- sub_specializers (Object s1, Object s2)
- {
- while (!NULLP (s1) && !NULLP (s2)) {
- if (!subtype (CAR (s1), CAR (s2))) {
- return (0);
- }
- s1 = CDR (s1);
- s2 = CDR (s2);
- }
-
- if (!NULLP (s1) || !NULLP (s2))
- return (0);
-
- return (1);
- }
-
- /* add a method, replacing one with matching parameters
- * if it's already there
- */
- Object
- add_method (Object generic, Object method)
- {
- Object new_specs, old_specs, methods, last, old_method;
-
- new_specs = function_specializers (method);
-
- /* check method for fit with generic specializers
- */
- old_specs = function_specializers (generic);
-
- if (!sub_specializers (new_specs, old_specs)) {
- error ("add-method: method specializers must be subtypes of generic func. specs.", method, NULL);
- }
- if (!GFRESTPARAM (generic) && METHRESTPARAM (method)) {
- error ("add-method: generic must have #rest parameters if method does",
- method,
- NULL);
- }
- methods = GFMETHODS (generic);
- last = NULL;
- while (!NULLP (methods)) {
- old_specs = function_specializers (CAR (methods));
- if (same_specializers (new_specs, old_specs)) {
- old_method = CAR (methods);
- if (!last) {
- GFMETHODS (generic) = cons (method, CDR (methods));
- return (construct_values (2, method, old_method));
- } else {
- CDR (last) = cons (method, CDR (methods));
- return (construct_values (2, method, old_method));
- }
- }
- last = methods;
- methods = CDR (methods);
- }
- GFMETHODS (generic) = cons (method, GFMETHODS (generic));
- return (construct_values (2, method, false_object));
- }
-
- static Object
- generic_function_methods (Object gen)
- {
- if (!GFUNP (gen)) {
- error ("generic-function-methods: argument must be a generic function", gen, NULL);
- }
- return (GFMETHODS (gen));
- }
-
- static Object
- generic_function_mandatory_keywords (Object generic)
- {
- return (GFKEYPARAMS (generic));
- }
-
- static Object
- function_specializers (Object func)
- {
- Object params;
-
- if (METHODP (func)) {
- params = METHREQPARAMS (func);
- } else if (GFUNP (func)) {
- params = GFREQPARAMS (func);
- } else {
- error ("function-specializers: arg. must be a method or generic function",
- func,
- NULL);
- }
- return make_specializers_from_params (params);
- }
-
- static Object
- function_values (Object func)
- {
- Object vals, rest;
-
- if (METHODP (func)) {
- vals = METHREQVALUES (func);
- rest = METHRESTVALUES (func);
- } else if (GFUNP (func)) {
- vals = GFREQVALUES (func);
- rest = GFRESTVALUES (func);
- } else {
- error ("function-values: arg. must be a method or generic function",
- func,
- NULL);
- }
- return construct_values (2,
- vals,
- rest == NULL ? false_object : rest);
-
- }
-
- static Object
- make_specializers_from_params (Object params)
- {
- Object specs, *tmp_ptr;
-
- for (specs = make_empty_list (), tmp_ptr = &specs;
- PAIRP (params);
- tmp_ptr = &CDR (*tmp_ptr), params = CDR (params)) {
- *tmp_ptr = cons (SECOND (CAR (params)), make_empty_list ());
-
- }
- return (specs);
-
- }
-
- /*
- returns three values:
- 1) number of required parameters
- 2) #t if takes rest, #f otherwise
- 3) sequence of keywords or #f if no keywords
- */
-
- static Object
- function_arguments (Object fun)
- {
- Object params, obj, keywords;
- Object has_rest;
-
- switch (POINTERTYPE (fun)) {
- case GenericFunction:
- params = GFREQPARAMS (fun);
- if (GFALLKEYS (fun)) {
- keywords = all_symbol;
- } else {
- keywords = GFKEYPARAMS (fun);
- }
- if (GFRESTPARAM (fun)) {
- has_rest = true_object;
- } else {
- has_rest = false_object;
- }
- break;
- case Method:
- params = METHREQPARAMS (fun);
- if (METHALLKEYS (fun)) {
- keywords = all_symbol;
- } else {
- keywords = METHKEYPARAMS (fun);
- }
- if (METHRESTPARAM (fun)) {
- has_rest = true_object;
- } else {
- has_rest = false_object;
- }
- break;
- case Primitive:
- error ("function-arguments: cannot query arguments of a primitive", fun, NULL);
- default:
- error ("function-arguments: bad argument", fun, NULL);
- }
- return (construct_values (3, list_length_int (params), has_rest, keywords));
- }
-
- static int
- find_keyword_in_list (Object keyword, Object keyword_list)
- {
- if (keyword_list == all_symbol) {
- return 1;
- } else {
- while (PAIRP (keyword_list)) {
- if (keyword == CAR (CAR (keyword_list))) {
- return 1;
- }
- keyword_list = CDR (keyword_list);
- }
- }
- return 0;
- }
-
- static Object
- user_applicable_method_p (Object argfun, Object sample_args)
- {
- applicable_method_p (argfun, sample_args, 1);
- }
-
- /*
- * In applicable_method_p, strict_check is true if we should complain
- * about extra keyword arguments. It should be set to 0 for internal
- * tests for generic function dispatch, etc.
- */
- static Object
- applicable_method_p (Object argfun, Object sample_args, int strict_check)
- {
- Object args, specs, samples, theargs, keywords, sample_keys;
- int num_required, i, no_rest_param, check_keywords = 1;
- Object funs, fun;
-
- if (!METHODP (argfun) && !GFUNP (argfun)) {
- error ("applicable-method?: first argument must be a generic function or method", fun, NULL);
- }
- if (METHODP (argfun)) {
- funs = cons (argfun, make_empty_list ());
- } else {
- strict_check = 0;
- funs = argfun;
- }
-
- while (PAIRP (funs)) {
- fun = CAR (funs);
- funs = CDR (funs);
- args = function_arguments (fun);
- specs = function_specializers (fun);
-
- /* Are there more sample args than required args?
- */
- num_required = INTVAL (FIRSTVAL (args));
- if (list_length (sample_args) < num_required) {
- return (false_object);
- }
- /* Do the types of the required args match the
- types of the sample args?
- */
- samples = sample_args;
- for (i = 0; i < num_required; ++i) {
- if (!instance (CAR (samples), CAR (specs))) {
- return (false_object);
- }
- samples = CDR (samples);
- specs = CDR (specs);
- }
-
- if (PAIRP (samples)) {
- keywords = THIRDVAL (args);
- /* If the method accepts keywords, make sure supplied keywords match */
- if (PAIRP (keywords) || keywords == all_symbol) {
- if (keywords == all_symbol) {
- check_keywords = 0;
- }
- /* If keywords != all_symbol, make sure rest of sample_args
- * are keyword specified, and that all keywords
- * in sample_args are in the keyword list
- */
- while (PAIRP (samples)) {
- if (!KEYWORDP (CAR (samples)) || EMPTYLISTP (CDR (samples))) {
- /* Has non keyword where our method needs one */
- return (false_object);
- } else if (check_keywords) {
- if (strict_check &&
- !find_keyword_in_list (CAR (samples), keywords)) {
- /* Has a keyword not in the method */
- return (false_object);
- }
- }
- samples = CDR (CDR (samples));
- }
- } else if (SECONDVAL (args) == false_object) {
- /* We have no rest parameter. If there are more arguments, this
- * ain't a match.
- */
- return (false_object);
- }
- }
- }
-
- /* We passed all of the tests.
- */
- return (true_object);
- }
-
- Object
- sorted_applicable_methods (Object fun, Object sample_args)
- {
- Object methods, app_methods, sorted_methods, method;
-
- methods = GFMETHODS (fun);
- app_methods = make_empty_list ();
- while (!NULLP (methods)) {
- method = CAR (methods);
- if (applicable_method_p (method, sample_args, 0) != false_object) {
- app_methods = cons (method, app_methods);
- }
- methods = CDR (methods);
- }
- if (NULLP (app_methods)) {
- return error ("no applicable methods", fun, sample_args, NULL);
- }
- return sort_methods (app_methods, sample_args);
- }
-
- /* See KLUDGE ALERT below */
- Object sort_driver_args____;
-
- static Object
- sort_methods (Object methods, Object sample_args)
- {
- Object method_vector;
- Object *prev_ptr, next;
- typedef int (*sortfun) ();
-
- /* KLUDGE ALERT!! Due to lack of closures in C, the following
- * is included as a public service to code readers.
- * We need the comparator for the sort to know about the
- * sample arguments. These are stored in the static global
- * sort_driver_args____.
- */
- sort_driver_args____ = sample_args;
-
- if (PAIRP (CDR (methods))) {
- method_vector = make_sov (methods);
- qsort (SOVELS (method_vector),
- SOVSIZE (method_vector),
- sizeof (Object),
- (sortfun) sort_driver);
-
- methods = vector_to_list (method_vector);
- }
- for (prev_ptr = &methods, next = CDR (methods);
- PAIRP (next);
- prev_ptr = &CDR (*prev_ptr), next = CDR (next)) {
- if (specializer_compare (function_specializers (CAR (*prev_ptr)),
- function_specializers (CAR (next))) == 0) {
- next = *prev_ptr;
- *prev_ptr = make_empty_list ();
- break;
- }
- }
- return construct_values (2, methods, next);
- }
-
- static int
- sort_driver (Object *pmeth1, Object *pmeth2)
- {
- Object specs1, specs2;
- int value;
-
- specs1 = function_specializers (*pmeth1);
- specs2 = function_specializers (*pmeth2);
- return specializer_compare (specs1, specs2);
- }
-
- /* It is assumed that s1 and s2 have the same length.
- */
- static int
- same_specializers (Object s1, Object s2)
- {
- while (!NULLP (s1) && !NULLP (s2)) {
- if (same_class_p (CAR (s1), CAR (s2)) == false_object) {
- return (0);
- }
- s1 = CDR (s1);
- s2 = CDR (s2);
- }
- if (!NULLP (s1) || !NULLP (s2))
- return (0);
- return (1);
- }
-
- static int
- specializer_compare (Object s1, Object s2)
- {
- Object spec1, spec2, arg, specs1, specs2, args, class_list;
- int ret = 0;
-
- specs1 = s1;
- specs2 = s2;
- args = sort_driver_args____;
-
- while (!NULLP (specs1)) {
- spec1 = CAR (specs1);
- spec2 = CAR (specs2);
- arg = CAR (args);
-
- if (spec1 == spec2) {
- /* No help from this specializer */
- } else if (subtype (spec1, spec2)) {
- /* This suggests less than */
- if (ret <= 0) {
- ret = -1;
- } else {
- /*
- * We previously saw an indication of greater than.
- * Thus, these two methods are unordered!
- */
- return 0;
- }
- } else if (subtype (spec2, spec1)) {
- /* This suggests greater than */
- if (ret >= 0) {
- ret = 1;
- } else {
- /* We previously saw an indication of less than. */
- return 0;
- }
- } else if (CLASSP (spec1) && CLASSP (spec2)) {
- for (class_list = CLASSPRECLIST (objectclass (arg));
- PAIRP (class_list);
- class_list = CDR (class_list)) {
- if (spec1 == CAR (class_list)) {
- if (ret <= 0) {
- ret = -1;
- break;
- } else {
- return 0;
- }
- } else if (spec2 == CAR (class_list)) {
- if (ret >= 0) {
- ret = 1;
- break;
- } else {
- return 0;
- }
- }
- }
- } else if (instance (arg, spec1)
- && instance (arg, spec2)
- && (!subtype (spec1, spec2))
- && (!subtype (spec2, spec1))) {
- /* These are ambiguous according to Design Note 8 */
- return 0;
- }
- specs1 = CDR (specs1);
- specs2 = CDR (specs2);
- args = CDR (args);
- }
- return ret;
- }
-
- static Object
- find_method (Object generic, Object spec_list)
- {
- Object methods, specs1, specs2;
-
- for (methods = GFMETHODS (generic);
- PAIRP (methods);
- methods = CDR (methods)) {
- if (same_specializers (function_specializers (CAR (methods)),
- spec_list)) {
- return CAR (methods);
- }
- }
- return false_object;
- }
-
- static Object
- remove_method (Object generic, Object method)
- {
- Object *tmp_ptr;
-
- for (tmp_ptr = &GFMETHODS (generic);
- PAIRP (*tmp_ptr);
- tmp_ptr = &CDR (*tmp_ptr)) {
- /* need to add test for sealed function, when available */
- if (method == CAR (*tmp_ptr)) {
- *tmp_ptr = CDR (*tmp_ptr);
- return method;
- }
- }
- error ("remove-method: generic function does not contain method",
- generic, method, NULL);
- }
-
- static Object
- debug_name_setter (Object method, Object name)
- {
- METHNAME (method) = name;
- return (name);
- }
-